package com.feonix.common.task;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.ScheduleBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;

import com.feonix.common.BaseInfo;
import com.feonix.common.util.ReflectionUtils;
import com.feonix.common.util.StringUtil;

public class TaskManager {
	protected static Log logger = LogFactory.getLog(TaskManager.class);
	public static final String FIRE_COUNT = "JOB_FIRE_COUNT";
	public static final String FIRE_COUNT_ERROR = "JOB_FIRE_COUNT_ERROR";
	public static final String CAN_PAUSE = "JOB_CAN_PAUSE";
	public static final String CAN_REMOVE = "JOB_CAN_REMOVE";
	private static Scheduler sched = null;

	// 获取Scheduler实例
	static {
		StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
		try {
			sched = stdSchedulerFactory.getScheduler();
			sched.start();
		} catch (SchedulerException schedulerException) {
			logger.error("create Scheduler error", schedulerException);
		}
	}

	public static void stopAllTask() {
		try {
			// 关闭Scheduler
			sched.shutdown();
			Thread.sleep(1000L);
			logger.debug("AllTask stop");
		} catch (Exception exception) {
			logger.error("stopAllTask error", exception);
		}
	}

	/**
	 * 新增任务，已存在的任务将不会被添加
	 * 
	 * @param tasks
	 */
	public static void addTask(BaseTask[] tasks) {
		if (ArrayUtils.isNotEmpty(tasks)) {
			for (BaseTask baseTask : tasks) {
				if (StringUtil.isEmpty(baseTask.taskId)) {
					logger.error(tasks.getClass() + " taskId IS NULL");
				} else if (baseTask.taskSchedule == null) {
					logger.error(baseTask.getClass() + " taskSchedule IS NULL");
				} else {
					// 具体任务
					JobDetail jobDetail = JobBuilder.newJob(baseTask.getClass()).withDescription(baseTask.taskName)
							.withIdentity(baseTask.taskId, baseTask.taskGroup).usingJobData(baseTask.dataMap).build();

					ArrayList localArrayList = new ArrayList();
					Object obj1;
					Object obj2;
					if (baseTask.taskSchedule instanceof Collection) {
						Collection taskScheduleCollection = (Collection) baseTask.taskSchedule;
						if (CollectionUtils.isNotEmpty(taskScheduleCollection)) {
							obj2 = null;
							int k = 0;
							for (Iterator iterator = taskScheduleCollection.iterator(); iterator.hasNext();) {
								Object taskScheduleBuilder = iterator.next();
								if (taskScheduleBuilder instanceof TaskScheduleBuilder) {
									String str = ((TaskScheduleBuilder) taskScheduleBuilder).getSchedule();

									obj2 = TriggerBuilder.newTrigger().withPriority(baseTask.priority)
											.withIdentity(baseTask.taskId + "-" + k, baseTask.taskGroup)
											.withDescription(baseTask.taskName).forJob(jobDetail);

									if (baseTask.startNow) {
										((TriggerBuilder) obj2).startNow();
									} else if (baseTask.startTime != null) {
										((TriggerBuilder) obj2).startAt(baseTask.startTime);
									}

									((TriggerBuilder) obj2).withSchedule(CronScheduleBuilder.cronSchedule(str))
											.forJob(jobDetail);
									localArrayList.add(((TriggerBuilder) obj2).build());
									++k;
								}
							}
						}
					} else {
						TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger()
								.withPriority(baseTask.priority).withIdentity(baseTask.taskId, baseTask.taskGroup)
								.withDescription(baseTask.taskName);
						if (baseTask.taskSchedule instanceof String) {
							obj2 = (String) baseTask.taskSchedule;
							if (StringUtil.isEmpty((String) obj2)) {
								continue;
							}
							triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule((String) obj2));
						} else if (baseTask.taskSchedule instanceof SimpleScheduleBuilder) {
							obj2 = (SimpleScheduleBuilder) baseTask.taskSchedule;
							if (obj2 == null) {
								continue;
							}
							if (baseTask.startNow) {
								triggerBuilder.startNow();
							} else if (baseTask.startTime != null) {
								triggerBuilder.startAt(baseTask.startTime);
							} else {
								long l = ((Long) ReflectionUtils.getFieldValue(obj2, "interval")).longValue();
								triggerBuilder.startAt(new Date(new Date().getTime() + l));
							}
							triggerBuilder.withSchedule((ScheduleBuilder) obj2);
						}
						localArrayList.add((triggerBuilder.forJob(jobDetail).build()));
					}
					try {
						if (sched.checkExists(jobDetail.getKey()))
							break;
						for (obj2 = localArrayList.iterator(); ((Iterator) obj2).hasNext();) {
							obj1 = (Trigger) ((Iterator) obj2).next();
							if (sched.checkExists(jobDetail.getKey()))
								sched.scheduleJob((Trigger) obj1);
							else
								sched.scheduleJob(jobDetail, (Trigger) obj1);
						}
					} catch (SchedulerException localSchedulerException) {
						logger.error("addTask error", localSchedulerException);
					} finally {
						localArrayList.clear();
					}
				}
			}
		}

	}

	/**
	 * 修改任务
	 * 
	 * @param tasks
	 */
	public static void modifyTask(BaseTask[] tasks) {
		if (tasks == null) {
			return;
		}
		for (BaseTask baseTask : tasks) {
			removeTask(baseTask.taskId, baseTask.taskGroup);
		}
		addTask(tasks);
	}

	/**
	 * 判断一个任务是否存在
	 * 
	 * @param taskId
	 * @return
	 */
	public static boolean isExist(String taskId) {
		return isExist(taskId, "DEFAULT");
	}

	/**
	 * 判断一个任务是否存在
	 * 
	 * @param taskId
	 * @param taskGroup
	 * @return
	 */
	public static boolean isExist(String taskId, String taskGroup) {
		JobKey jobKey = JobKey.jobKey(taskId, taskGroup);
		boolean bool = false;
		try {
			bool = sched.checkExists(jobKey);
		} catch (SchedulerException schedulerException) {
			logger.error("check isExist error", schedulerException);
		}
		return bool;
	}

	/**
	 * 暂停一个任务
	 * 
	 * @param taskId
	 */
	public static void pauseTask(String taskId) {
		pauseTask(taskId, "DEFAULT");
	}

	/**
	 * 暂停一个任务
	 * 
	 * @param taskId
	 * @param taskGroup
	 */
	public static void pauseTask(String taskId, String taskGroup) {
		try {
			JobKey jobKey = JobKey.jobKey(taskId, taskGroup);
			JobDetail jobDetail = sched.getJobDetail(jobKey);
			if ((jobDetail != null) && (jobDetail.getJobDataMap().getBoolean("JOB_CAN_PAUSE"))) {
				List<? extends Trigger> triggerList = getTrigers(jobKey);
				for (Trigger trigger : triggerList)
					sched.pauseTrigger(trigger.getKey());
			}
		} catch (SchedulerException schedulerException) {
			logger.error("stopTask error", schedulerException);
		}
	}

	/**
	 * 恢复一个任务
	 * 
	 * @param taskId
	 */
	public static void resumeTask(String taskId) {
		resumeTask(taskId, "DEFAULT");
	}

	/**
	 * 恢复一个任务
	 * 
	 * @param taskId
	 * @param taskGroup
	 */
	public static void resumeTask(String taskId, String taskGroup) {
		try {
			JobKey jobKey = JobKey.jobKey(taskId, taskGroup);
			List<? extends Trigger> triggerList = getTrigers(jobKey);
			for (Trigger trigger : triggerList)
				sched.resumeTrigger(trigger.getKey());
		} catch (SchedulerException schedulerException) {
			logger.error("stopTask error", schedulerException);
		}
	}

	/**
	 * 删除一个任务
	 * 
	 * @param taskId
	 */
	public static void removeTask(String taskId) {
		removeTask(taskId, "DEFAULT");
	}

	/**
	 * 删除一个任务
	 * 
	 * @param taskId
	 * @param taskGroup
	 */
	public static void removeTask(String taskId, String taskGroup) {
		try {
			JobKey jobKey = JobKey.jobKey(taskId, taskGroup);
			JobDetail jobDetail = sched.getJobDetail(jobKey);
			if ((jobDetail != null) && (jobDetail.getJobDataMap().getBoolean("JOB_CAN_REMOVE"))) {
				List<? extends Trigger> triggerList = getTrigers(jobKey);
				for (Trigger trigger : triggerList) {
					sched.pauseTrigger(trigger.getKey());
					sched.unscheduleJob(trigger.getKey());
					sched.deleteJob(jobKey);
				}
			}
		} catch (SchedulerException schedulerException) {
			logger.error("removeTask error", schedulerException);
		}
	}

	/**
	 * 获得所有任务
	 * 
	 * @return
	 */
	public static List<Trigger> getAllTask() {
		ArrayList<Trigger> resultList = new ArrayList<Trigger>();
		try {
			List<String> jobGroupNames = sched.getJobGroupNames();
			for (String str : jobGroupNames)
				for (JobKey jobKey : sched.getJobKeys(GroupMatcher.jobGroupEquals(str))) {
					List<? extends Trigger> triggerList = sched.getTriggersOfJob(jobKey);
					for (Trigger trigger : triggerList)
						resultList.add(trigger);
				}
		} catch (Exception exception) {
			logger.error("getAllTask error", exception);
		}
		return resultList;
	}

	/**
	 * 获得一个job
	 * 
	 * @param jobKey
	 * @return
	 */
	public static JobDetail getJobDetail(JobKey jobKey) {
		JobDetail jobDetail = null;
		try {
			jobDetail = sched.getJobDetail(jobKey);
		} catch (SchedulerException schedulerException) {
			logger.error("getJobDetail error", schedulerException);
		}
		return jobDetail;
	}

	/**
	 * 获得一个触发器的状态，默认组
	 * 
	 * @param triggerId
	 * @return
	 */
	public static TaskState getTriggerState(String triggerId) {
		return getTriggerState(triggerId, "DEFAULT");
	}

	/**
	 * 获得一个触发器的状态
	 * 
	 * @param triggerId
	 * @param triggerGroup
	 * @return
	 */
	public static TaskState getTriggerState(String triggerId, String triggerGroup) {
		TriggerKey triggerKey = TriggerKey.triggerKey(triggerId, triggerGroup);
		TriggerState triggerState = getTriggerState(triggerKey);
		return convertState(triggerState);
	}

	/**
	 * 获得一个任务的状态
	 * 
	 * @param taskId
	 * @return
	 */
	public static TaskState getTaskState(String taskId) {
		return getTaskState(taskId, "DEFAULT");
	}

	/**
	 * 获得一个任务的状态
	 * 
	 * @param taskId
	 * @param taskGroup
	 * @return
	 */
	public static TaskState getTaskState(String taskId, String taskGroup) {
		TaskState taskState = TaskState.NONE;
		List<? extends Trigger> trigerList = getTrigers(JobKey.jobKey(taskId, taskGroup));
		if (CollectionUtils.isNotEmpty(trigerList)) {
			Iterator<? extends Trigger> iterator = trigerList.iterator();
			if (iterator.hasNext()) {
				Trigger trigger = iterator.next();
				Trigger.TriggerState triggerState = getTriggerState(trigger.getKey());
				taskState = convertState(triggerState);
			}
		}

		return taskState;
	}

	/**
	 * 立即启动一个任务
	 * 
	 * @param taskId
	 */
	public static void startNow(String taskId) {
		startNow(taskId, "DEFAULT");
	}

	/**
	 * 立即启动一个任务
	 * 
	 * @param taskId
	 * @param taskGroup
	 */
	public static void startNow(String taskId, String taskGroup) {
		try {
			sched.triggerJob(JobKey.jobKey(taskId, taskGroup));
		} catch (Exception exception) {
			logger.error("startNow error", exception);
		}
	}

	private static TaskState convertState(TriggerState triggerState) {
		TaskState taskState = null;
		switch (triggerState.ordinal() + 1) {
		case 6:
			taskState = TaskState.RUNNING;
			break;
		case 4:
			taskState = TaskState.COMPLETE;
			break;
		case 5:
			taskState = TaskState.ERROR;
			break;
		case 1:
			taskState = TaskState.NONE;
			break;
		case 2:
			taskState = TaskState.WATTING;
			break;
		case 3:
			taskState = TaskState.PAUSED;
			break;
		default:
			taskState = TaskState.NONE;
		}

		return taskState;
	}

	private static TriggerState getTriggerState(TriggerKey triggerKey) {
		TriggerState triggerState = null;
		try {
			triggerState = sched.getTriggerState(triggerKey);
		} catch (SchedulerException schedulerException) {
			logger.error("getJobState error", schedulerException);
		}
		return triggerState;
	}

	private static List<? extends Trigger> getTrigers(JobKey jobKey) {
		List<? extends Trigger> triggerList = null;
		try {
			triggerList = sched.getTriggersOfJob(jobKey);
		} catch (SchedulerException schedulerException) {
			logger.error("getTrigers error", schedulerException);
		}
		return triggerList;
	}

	/**
	 * 获得下次启动时间
	 * 
	 * @param taskId
	 * @return
	 */
	public static Date[] getNextFireTime(String taskId) {
		return getNextFireTime(taskId, "DEFAULT");
	}

	/**
	 * 获得下次启动时间
	 * 
	 * @param taskId
	 * @param group
	 * @return
	 */
	public static Date[] getNextFireTime(String taskId, String group) {
		List<? extends Trigger> triggerList = getTrigers(JobKey.jobKey(taskId, group));
		Date[] dateArray = null;
		if (CollectionUtils.isNotEmpty(triggerList)) {
			dateArray = new Date[triggerList.size()];
			int i = 0;
			for (Trigger trigger : triggerList) {
				dateArray[i] = trigger.getNextFireTime();
				++i;
			}
		}
		return dateArray;
	}
}
